package com.demo.aop;

import com.alibaba.fastjson.JSON;
import com.demo.annotation.ValidResult;
import com.demo.model.common.MsgCode;
import com.demo.model.common.MsgMap;
import com.demo.util.LoggerUtils;
import com.demo.util.RequestUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * IntelliJ IDEA.
 * User: lwb
 * Date: 2017/10/18
 * Time: 14:50
 * function:
 */
@Aspect
@Component
public class AroundAspect {

    @Around("execution(* com.demo.control..*.*(..)) && @annotation(org.springframework.web.bind.annotation.ResponseBody)")//注解类型也必须是全限定类型名
    public Object aroundMethod(ProceedingJoinPoint point)
    {
        Object obj = null;
        String methodName = point.getSignature().getName();
        try
        {
            //入参数输出
            Map<String , String> map = RequestUtil.getParameterMap();
            LoggerUtils.debug(methodName + "--->:" + JSON.toJSONString(map));

            //检测是否有参数校验是否通过
            obj = validParams(point, methodName);
            if (obj != null) return obj;

            obj = point.proceed();

            //结果输出
            LoggerUtils.debug(  "return --->:" + obj);

        }catch (Throwable e)
        {
            LoggerUtils.error(e.getMessage() , e);
            if(obj == null) {
                MsgMap msgMap = new MsgMap();
                msgMap.putCode(MsgCode.ERROR);
                if(obj instanceof  MsgMap)
                    obj = msgMap;
            }
        }
        return obj;
    }

    /**
     *
     * @param point
     * @param methodName
     * @return null 没有参数校验或校证通过 ， 不为空参数校验不通过
     */
    private MsgMap validParams(ProceedingJoinPoint point, String methodName) {
        Method method = getMethodByClassAndName(point.getTarget().getClass() , methodName);
        Annotation[][] annotations = method.getParameterAnnotations();
        Object[] args = point.getArgs();
        if(annotations != null)
        {
            for(int i = 0 ; i < annotations.length ; i++)
            {
                Annotation[] anno = annotations[i];
                for(int j = 0 ; j < anno.length ; j++)
                {
                    if(anno[j].annotationType().equals(ValidResult.class))
                    {
                        Object ojbect = args[i];
                        BindingResult result = (BindingResult) ojbect;
                        LoggerUtils.debug(JSON.toJSONString("aop--》：" + getErrors(result)));
                        if(result.hasErrors())
                        {
                            MsgMap msgMap = new MsgMap();
                            msgMap.putCode(MsgCode.PARAMETER_VALUES_ERROR);
                            Map errMap = getErrors(result);
                            msgMap.put("errs" , errMap);
                            msgMap.putMsg("参数不合法");
                            LoggerUtils.debug(JSON.toJSONString(errMap));
                            return msgMap;
                        }
                    }
                }
            }
        }
        return null;
    }

    private Map<String, String> getErrors(BindingResult result) {
        Map<String, String> map = new HashMap<String, String>();
        List<FieldError> list = result.getFieldErrors();
        for (FieldError error : list) {
            map.put(error.getField(), error.getDefaultMessage());
        }
        return map;
    }
    private Method getMethodByClassAndName(Class<? extends Object> clazz, String methodName)
    {
        Method[] methods = clazz.getDeclaredMethods();
        for(Method m : methods)
        {
            if(methodName.equals(m.getName()))
            {
                return m;
            }
        }
        return null;
    }

}
